#include <pthread.h>
#include "Thread.hpp"
#include <iostream>
#include <cstdlib>
#include <vector>
#include <fcntl.h>
#include <functional>
#include <unistd.h>
#include "LockGuard.hpp"
#include <mutex>
using namespace std;
using namespace zzz;

// 对线程的数据进行封装
class ThreadData
{
public:
    ThreadData(string &thread, int &ticket)
        : _threadname(thread), _ticket(ticket), _total(0)
    {
    }

    string _threadname;
    int _total;
    int &_ticket;
};

int g_val = 1000;

void testfun(ThreadData &d)
{
    while (1)
    {
        if (d._ticket > 0)
        {
            cout << d._threadname << " get a ticket:" << d._ticket << endl;
            usleep(2000);
            d._ticket--;
            d._total++;
        }
        else if (d._ticket <= 0)
        {
            cout << "no ticket" << endl;
            break;
        }
    }
}

int main()
{
    std::vector<Thread<ThreadData>> pths;
    std::vector<ThreadData *> das;

    for (int i = 0; i < 5; i++)
    {
        std::string tname = "thread-" + std::to_string(i + 1);

        ThreadData *p = new ThreadData(tname, g_val);
        das.emplace_back(p);

        pths.emplace_back(testfun, *p, tname);
    }
    for (auto &thread : pths)
    {
        thread.start();
    }
    for (auto &thread : pths)
    {
        thread.join();
    }
    for (auto &p : das)
    {
        cout << p->_threadname << "::" << p->_total << endl;
    }
    cout << "main end" << endl;
    return 0;
}

// 全局锁
// pthread_mutex_t gmutex = PTHREAD_MUTEX_INITIALIZER; // 定义锁

// //pthread_mutex_t gmutex;
// //pthread_mutex_init(&gmutex, nullptr);       //error:调用函数必须在函数体内

// int g_val = 1000;

// void testfun(ThreadData &d)
// {
//     while (1)
//     {
//         pthread_mutex_lock(&gmutex); // 加锁
//         if (d._ticket > 0)
//         {
//             usleep(1000);
//             cout << d._threadname << " get a ticket:" << d._ticket << endl;
//             d._ticket--;

//             pthread_mutex_unlock(&gmutex); // 解锁
//             d._total++;
//         }
//         else if (d._ticket <= 0)
//         {
//             pthread_mutex_unlock(&gmutex); // 解锁
//             cout << "no ticket" << endl;
//             break;
//         }
//     }
// }

// int main()
// {
//     std::vector<Thread<ThreadData>> pths;
//     std::vector<ThreadData *> das;

//     for (int i = 0; i < 5; i++)
//     {
//         std::string tname = "thread-" + std::to_string(i + 1);
//         ThreadData *p = new ThreadData(tname, g_val);
//         das.emplace_back(p);

//         pths.emplace_back(testfun, *p, tname);
//     }
//     for (auto &thread : pths)
//     {
//         thread.start();
//     }
//     for (auto &thread : pths)
//     {
//         thread.join();
//     }
//     for (auto &p : das)
//     {
//         cout << p->_threadname << "::" << p->_total << endl;
//     }
//     cout << "main end" << endl;

//     return 0;
// }

//// 局部锁
// class ThreadData
// {
// public:
//     ThreadData(string &thread, int &ticket, pthread_mutex_t &mutex)
//         : _threadname(thread), _ticket(ticket), _total(0), _mutex(mutex)
//     {
//     }

//     string _threadname;
//     int _total;
//     int &_ticket;
//     pthread_mutex_t &_mutex;
// };

// int g_val = 1000;

// void testfun(ThreadData &d)
// {
//     while (1)
//     {
//         pthread_mutex_lock(&d._mutex);
//         if (d._ticket > 0)
//         {
//             usleep(1000);
//             cout << d._threadname << " get a ticket:" << d._ticket << endl;
//             d._ticket--;
//             pthread_mutex_unlock(&d._mutex);
//             d._total++;
//         }
//         else if (d._ticket <= 0)
//         {
//             pthread_mutex_unlock(&d._mutex);
//             cout << "no ticket" << endl;
//             break;
//         }
//     }
// }

// int main()
// {
//     std::vector<Thread<ThreadData>> pths;
//     std::vector<ThreadData *> das;

//     pthread_mutex_t mutex;
//     pthread_mutex_init(&mutex, nullptr);

//     // pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; // 定义锁

//     for (int i = 0; i < 5; i++)
//     {
//         std::string tname = "thread-" + std::to_string(i + 1);
//         ThreadData *p = new ThreadData(tname, g_val, mutex);
//         das.emplace_back(p);

//         pths.emplace_back(testfun, *p, tname);
//     }
//     for (auto &thread : pths)
//     {
//         thread.start();
//     }
//     for (auto &thread : pths)
//     {
//         thread.join();
//     }
//     for (auto &p : das)
//     {
//         cout << p->_threadname << "::" << p->_total << endl;
//     }

//     pthread_mutex_destroy(&mutex);

//     cout << "main end" << endl;

//     return 0;
// }

// // 局部锁 —— 使用封装的锁
// class ThreadData
// {
// public:
//     ThreadData(string &thread, int &ticket, pthread_mutex_t &mutex)
//         : _threadname(thread), _ticket(ticket), _total(0), _mutex(mutex)
//     {
//     }

//     string _threadname;
//     int _total;
//     int &_ticket;
//     pthread_mutex_t &_mutex;
// };

// int g_val = 1000;

// void testfun(ThreadData &d)
// {
//     while (1)
//     {
//         LockGuard guard(&d._mutex);
//         if (d._ticket > 0)
//         {
//             usleep(1000);
//             cout << d._threadname << " get a ticket:" << d._ticket << endl;
//             d._ticket--;
//             d._total++;
//         }
//         else if (d._ticket <= 0)
//         {
//             cout << "no ticket" << endl;
//             break;
//         }
//     }
// }

// int main()
// {
//     std::vector<Thread<ThreadData>> pths;
//     std::vector<ThreadData *> das;

//     // pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

//     pthread_mutex_t mutex;
//     pthread_mutex_init(&mutex, nullptr);

//     for (int i = 0; i < 5; i++)
//     {
//         std::string tname = "thread-" + std::to_string(i + 1);
//         ThreadData *p = new ThreadData(tname, g_val, mutex);
//         das.emplace_back(p);

//         pths.emplace_back(testfun, *p, tname);
//     }
//     for (auto &thread : pths)
//     {
//         thread.start();
//     }
//     for (auto &thread : pths)
//     {
//         thread.join();
//     }
//     for (auto &p : das)
//     {
//         cout << p->_threadname << "::" << p->_total << endl;
//     }

//     pthread_mutex_destroy(&mutex);

//     cout << "main end" << endl;

//     return 0;
// }

// // 局部锁 —— C++11 的锁
// class ThreadData
// {
// public:
//     ThreadData(string &thread, int &ticket, std::mutex &mutex)
//         : _threadname(thread), _ticket(ticket), _total(0), _mutex(mutex)
//     {
//     }

//     string _threadname;
//     int _total;
//     int &_ticket;
//     std::mutex &_mutex;
// };

// int g_val = 1000;

// // void testfun(ThreadData &d)
// // {
// //     while (1)
// //     {
// //         d._mutex.lock();
// //         if (d._ticket > 0)
// //         {
// //             usleep(1000);
// //             cout << d._threadname << " get a ticket:" << d._ticket << endl;
// //             d._ticket--;
// //             d._mutex.unlock();
// //             d._total++;
// //         }
// //         else if (d._ticket <= 0)
// //         {
// //             d._mutex.unlock();
// //             cout << "no ticket" << endl;
// //             break;
// //         }
// //     }
// // }

// void testfun(ThreadData &d)
// {
//     while (1)
//     {
//         std::lock_guard<std::mutex> guard(d._mutex);

//         if (d._ticket > 0)
//         {
//             usleep(1000);
//             cout << d._threadname << " get a ticket:" << d._ticket << endl;
//             d._ticket--;
//             d._total++;
//         }
//         else if (d._ticket <= 0)
//         {
//             cout << "no ticket" << endl;
//             break;
//         }
//     }
// }

// int main()
// {
//     std::vector<Thread<ThreadData>> pths;
//     std::vector<ThreadData *> das;

//     std::mutex aaa;

//     for (int i = 0; i < 5; i++)
//     {
//         std::string tname = "thread-" + std::to_string(i + 1);
//         ThreadData *p = new ThreadData(tname, g_val, aaa);
//         das.emplace_back(p);

//         pths.emplace_back(testfun, *p, tname);
//     }
//     for (auto &thread : pths)
//     {
//         thread.start();
//     }
//     for (auto &thread : pths)
//     {
//         thread.join();
//     }
//     for (auto &p : das)
//     {
//         cout << p->_threadname << "::" << p->_total << endl;
//     }
//     cout << "main end" << endl;

//     return 0;
// }